<!DOCTYPE html>
<html><head>
<title>用Unity3D实现打飞碟游戏</title>




<meta charset="utf-8">
<meta name="X-UA-Compatible" content="IE=edge">
<meta name="google-site-verification" content="">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
<meta content="telephone=no" name="format-detection">
<meta name="description" content="">
<meta name="renderer" content="webkit">
<meta name="theme-color" content="#ffffff">



<meta property="og:title" content="用Unity3D实现打飞碟游戏" />
<meta property="og:description" content="用Unity3D实现【打飞碟小游戏】  相关链接 项目仓库：https://gitee.com/WondrousWisdomcard/unity3d-homework
项目文档：https://gitee.com/WondrousWisdomcard/unity3d-homework/blob/master/Homework04/%E9%A1%B9%E7%9B%AE%E6%96%87%E6%A1%A3.md
演示视频：
  非物理引擎版本：https://www.bilibili.com/video/BV1zT4y1R7TY?spm_id_from=333.999.0.0
  物理引擎版本：https://www.bilibili.com/video/BV1Rb4y1h72z?spm_id_from=333.999.0.0
   游戏规则 简单地说：这是一个打飞碟小游戏（鼠标打），这是一样非常考验反应和手速的小游戏，不同的小飞碟会从大飞碟中飞出，我们点击小飞碟即可将其轰炸。不同等级的小飞碟的分数不同（黑色飞碟高达5000分！），五回合下来，累计最终得分。
这次作业的亮点在于引入了工厂模式、对象池和物理引擎，我们将一一介绍，但首先介绍how to make a simple飞碟。
How to make a simple 飞碟 飞碟由一个Y轴压扁的球和一个小球组成，里面包含一个小球，它们的Transform数据如下，内部小球是外部环的子对象，所以它的大小对于外部环的相对大小。
   外部小环 内部小球 物理属性（外部小环）           我们给它增加一个 RigidBody 组件和 ConstantForce 组件，并为它添加力矩（Torque），这样它就可以轻轻摇摆了。
接下来，我们为它配色，可以用图片（Texture2D），也可以直接创建Material，把设置了颜色的 Material 拖到飞碟上就可以了。
最后把他拖到 Assets 栏形成预制，会轻轻摆动的飞碟就做好了。
 我做的游戏中间有个大飞碟，它使用同样的预制，只不过体型稍大，并设置他不受重力的影响，位置固定（不然它会被小飞碟撞飞）
 工厂模式、对象池和对象复用 工厂模式（Factory Pattern）是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式，它提供了一种创建对象的最佳方式。在工厂模式中，我们在创建对象时不会对客户端暴露创建逻辑，并且是通过使用一个共同的接口来指向新创建的对象。
在游戏中，因为要创建大量飞碟，我们为飞碟创建了一个飞碟工厂类，控制器通过调用飞碟工厂提供的方法来产生飞碟和释放飞碟。
飞碟工厂对控制器和其他模块隐蔽了飞碟的产生和释放细节。在飞碟工厂内部，我们通过维护两个队列来实现一个飞碟对象池，避免频繁地系统调用来生成对象。
在实际游戏过程中，由于飞碟的需求随着回合数的增加而变大，对象池还是经常处于“不够用”状态，再加上我设计时，每种等级飞碟使用不同的预制，使得对象的复用不是在空闲队列里随便取一个就行的，而是要去的相同等级的飞碟对象（这样它们的预制才是一样的，游戏对象也才符合）。因此每次都需要遍历对象池，寻找合适的空闲飞碟对象。
使用不同预制创建对象出现一个很尴尬的情况，因为每次创建飞碟的等级都是随机选取的，导致可能会出现：空闲池有很多不同等级飞碟，但都无一满足当前所需的飞碟等级。但是，随着飞碟需求数目的增加，这种供不应需的状况就越不会出现，对象池各种等级的空闲飞碟都会存在。
以下是 DiskFactory 类的代码：" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://wondrouswisdomcard.gitee.io/posts/unity3d3/" />
<meta property="article:published_time" content="2021-10-24T00:00:00+00:00" />
<meta property="article:modified_time" content="2021-10-24T00:00:00+00:00" /><meta property="og:site_name" content="My Blog" />





<meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="用Unity3D实现打飞碟游戏"/>
<meta name="twitter:description" content="用Unity3D实现【打飞碟小游戏】  相关链接 项目仓库：https://gitee.com/WondrousWisdomcard/unity3d-homework
项目文档：https://gitee.com/WondrousWisdomcard/unity3d-homework/blob/master/Homework04/%E9%A1%B9%E7%9B%AE%E6%96%87%E6%A1%A3.md
演示视频：
  非物理引擎版本：https://www.bilibili.com/video/BV1zT4y1R7TY?spm_id_from=333.999.0.0
  物理引擎版本：https://www.bilibili.com/video/BV1Rb4y1h72z?spm_id_from=333.999.0.0
   游戏规则 简单地说：这是一个打飞碟小游戏（鼠标打），这是一样非常考验反应和手速的小游戏，不同的小飞碟会从大飞碟中飞出，我们点击小飞碟即可将其轰炸。不同等级的小飞碟的分数不同（黑色飞碟高达5000分！），五回合下来，累计最终得分。
这次作业的亮点在于引入了工厂模式、对象池和物理引擎，我们将一一介绍，但首先介绍how to make a simple飞碟。
How to make a simple 飞碟 飞碟由一个Y轴压扁的球和一个小球组成，里面包含一个小球，它们的Transform数据如下，内部小球是外部环的子对象，所以它的大小对于外部环的相对大小。
   外部小环 内部小球 物理属性（外部小环）           我们给它增加一个 RigidBody 组件和 ConstantForce 组件，并为它添加力矩（Torque），这样它就可以轻轻摇摆了。
接下来，我们为它配色，可以用图片（Texture2D），也可以直接创建Material，把设置了颜色的 Material 拖到飞碟上就可以了。
最后把他拖到 Assets 栏形成预制，会轻轻摆动的飞碟就做好了。
 我做的游戏中间有个大飞碟，它使用同样的预制，只不过体型稍大，并设置他不受重力的影响，位置固定（不然它会被小飞碟撞飞）
 工厂模式、对象池和对象复用 工厂模式（Factory Pattern）是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式，它提供了一种创建对象的最佳方式。在工厂模式中，我们在创建对象时不会对客户端暴露创建逻辑，并且是通过使用一个共同的接口来指向新创建的对象。
在游戏中，因为要创建大量飞碟，我们为飞碟创建了一个飞碟工厂类，控制器通过调用飞碟工厂提供的方法来产生飞碟和释放飞碟。
飞碟工厂对控制器和其他模块隐蔽了飞碟的产生和释放细节。在飞碟工厂内部，我们通过维护两个队列来实现一个飞碟对象池，避免频繁地系统调用来生成对象。
在实际游戏过程中，由于飞碟的需求随着回合数的增加而变大，对象池还是经常处于“不够用”状态，再加上我设计时，每种等级飞碟使用不同的预制，使得对象的复用不是在空闲队列里随便取一个就行的，而是要去的相同等级的飞碟对象（这样它们的预制才是一样的，游戏对象也才符合）。因此每次都需要遍历对象池，寻找合适的空闲飞碟对象。
使用不同预制创建对象出现一个很尴尬的情况，因为每次创建飞碟的等级都是随机选取的，导致可能会出现：空闲池有很多不同等级飞碟，但都无一满足当前所需的飞碟等级。但是，随着飞碟需求数目的增加，这种供不应需的状况就越不会出现，对象池各种等级的空闲飞碟都会存在。
以下是 DiskFactory 类的代码："/>







<script src="/vendor/js/jquery.min.js" ></script>
<script src="/vendor/js/popper.min.js" ></script>
<script src="/vendor/js/bootstrap.min.js" ></script>
<script src="/vendor/js/smooth-scroll.polyfills.min.js" ></script>
<link type="text/css" rel="stylesheet" href="/vendor/css/bootstrap.min.css">
<script src="/vendor/js/vue.min.js" ></script>






<link rel="stylesheet" href="https://wondrouswisdomcard.gitee.io/scss/journal.min.c116bc90d171283f099f173854157ec8f183f9073b93443b2c8ad82899ee9025.css" integrity="sha256-wRa8kNFxKD8Jnxc4VBV&#43;yPGD&#43;Qc7k0Q7LIrYKJnukCU=" media="screen">



<link rel="stylesheet" href="https://wondrouswisdomcard.gitee.io/scss/dark-mode.min.552aae4638a84aa57cf0b195750a49ea9131d3bb621d1ed3ebc9b14b18166536.css" integrity="sha256-VSquRjioSqV88LGVdQpJ6pEx07tiHR7T68mxSxgWZTY=" media="screen">


<script src="https://wondrouswisdomcard.gitee.io/js/loadCSS.js"></script>
<script>
  loadCSS("https://fonts.googleapis.com/css?family=Lora|Montserrat|Fira+Mono|Noto+Serif+SC|Material+Icons");
</script>




  
    <script src="https://wondrouswisdomcard.gitee.io/js/toc-collapse.js"></script>
  



<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css">
<script src="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js"></script>
<script src="/vendor/js/md5.min.js"></script>
<script>
  var gitalk = new Gitalk({
  clientID: 'your client id',
  clientSecret: 'your client secret',
  repo: 'repo name',
  owner: 'user',
  admin: ['user'],
  id: md5(location.pathname),
  distractionFreeMode: 'false'
  });
  window.onload = function () {
        gitalk.render('gitalk-container')
  }
</script>







<script src="https://cdn.jsdelivr.net/npm/vue-disqus@3/dist/vue-disqus.js"></script>


</head>
<body>
    	<div id="app"><div ref="sideContainer" class="side-container">
    
    <a class="a-block nav-head false" href="https://wondrouswisdomcard.gitee.io">
    
        <div class="nav-title">
            Wondrous WindomCard&#39;s Blog
        </div>
        
        <div class="nav-subtitle">
            Themed by Diary.
        </div>
        
    </a>

    <div class="nav-link-list">
        
        
            
            
            
                
            
            
            
            <a class="a-block nav-link-item active" href="/posts">
                Archive
            </a>
            
        
            
            
            
            
            
            <a class="a-block nav-link-item false" href="/categories">
                Categories
            </a>
            
        
            
            
            
            
            
            <a class="a-block nav-link-item false" href="/tags">
                Tags
            </a>
            
        
            
            
            
            
            
            <a class="a-block nav-link-item false" href="/index.xml">
                RSS Feed
            </a>
            
        
    </div>

    

    <div class="nav-footer">
        
Hugo Theme <a href="https://github.com/amazingrise/hugo-theme-diary">Diary</a> by <a href="https://amazingrise.net">Rise</a>
<br>
Ported from <a href="https://mak1t0.cc/" target="_blank" rel="noreferrer noopener">Makito</a>'s <a href="https://github.com/SumiMakito/hexo-theme-journal/" target="_blank" rel="noreferrer noopener">Journal.</a> <br>
<br>

&copy;
	
	This is a customized copyright.
	

    </div>
    
</div><div ref="extraContainer" class="extra-container">
    
    
    <div class="toc animated-visibility" :class="{ invisible: scrollY <= 140 }">


	<div class="toc-content">
	
		
		
		
		<center>- CATALOG -</center>
		
		
		<ul>
			
				
				
					
						
						
						
						
						
							<li>
								<a href="#%e7%94%a8unity3d%e5%ae%9e%e7%8e%b0%e6%89%93%e9%a3%9e%e7%a2%9f%e5%b0%8f%e6%b8%b8%e6%88%8f" onclick="onNavClick(`#用unity3d实现打飞碟小游戏-nav`)" id="用unity3d实现打飞碟小游戏-nav">
									用Unity3D实现【打飞碟小游戏】
								</a>
							</li>
						
						
					
				
			
				
				
					
						
						
						
						
							
								<ul class="collapse" data-toggle="collapse">
							
						
						
							<li>
								<a href="#%e7%9b%b8%e5%85%b3%e9%93%be%e6%8e%a5" onclick="onNavClick(`#相关链接-nav`)" id="相关链接-nav">
									相关链接
								</a>
							</li>
						
						
					
				
			
				
				
					
						
						
						
						
						
							<li>
								<a href="#%e6%b8%b8%e6%88%8f%e8%a7%84%e5%88%99" onclick="onNavClick(`#游戏规则-nav`)" id="游戏规则-nav">
									游戏规则
								</a>
							</li>
						
						
					
				
			
				
				
					
						
						
						
						
							
								<ul class="collapse" data-toggle="collapse">
							
						
						
							<li>
								<a href="#how-to-make-a-simple-%e9%a3%9e%e7%a2%9f" onclick="onNavClick(`#how-to-make-a-simple-飞碟-nav`)" id="how-to-make-a-simple-飞碟-nav">
									How to make a simple 飞碟
								</a>
							</li>
						
						
					
				
			
				
				
					
						
						
						
						
						
							<li>
								<a href="#%e5%b7%a5%e5%8e%82%e6%a8%a1%e5%bc%8f%e5%af%b9%e8%b1%a1%e6%b1%a0%e5%92%8c%e5%af%b9%e8%b1%a1%e5%a4%8d%e7%94%a8" onclick="onNavClick(`#工厂模式对象池和对象复用-nav`)" id="工厂模式对象池和对象复用-nav">
									工厂模式、对象池和对象复用
								</a>
							</li>
						
						
					
				
			
				
				
					
						
						
						
						
						
							<li>
								<a href="#%e7%89%a9%e7%90%86%e5%bc%95%e6%93%8e" onclick="onNavClick(`#物理引擎-nav`)" id="物理引擎-nav">
									物理引擎
								</a>
							</li>
						
						
					
				
			
		</ul>
	</div>

</div>
    
    <div class="pagination">
        <a id="globalBackToTop" class="pagination-action animated-visibility" href="#top" :class="{ invisible: scrollY == 0 }">
            <i class="material-icons pagination-action-icon">
                keyboard_arrow_up
            </i>
        </a>
        
        <a class="pagination-action" v-on:click="toggleDarkMode">
            <i class="material-icons pagination-action-icon" v-if="isDarkMode">
                brightness_4
            </i>
            <i class="material-icons pagination-action-icon" v-else="isDarkMode">
                brightness_7
            </i>
        </a>
        
        
    </div>
</div>
<div class="single-column-drawer-container" ref="drawer"
     v-bind:class="{ 'single-column-drawer-container-active': isDrawerOpen }">
    <div class="drawer-content">
        <div class="drawer-menu">
            
            
            
                
                
                
                    
                
                
                
                <a class="a-block drawer-menu-item active" href="/posts">
                    Archive
                </a>
                
            
                
                
                
                
                
                <a class="a-block drawer-menu-item false" href="/categories">
                    Categories
                </a>
                
            
                
                
                
                
                
                <a class="a-block drawer-menu-item false" href="/tags">
                    Tags
                </a>
                
            
                
                
                
                
                
                <a class="a-block drawer-menu-item false" href="/index.xml">
                    RSS Feed
                </a>
                
            
            
            <div class="toc">


	<div class="toc-content">
	
		
		
		
		<center>- CATALOG -</center>
		
		
		<ul>
			
				
				
					
						
						
						
						
						
							<li>
								<a href="#%e7%94%a8unity3d%e5%ae%9e%e7%8e%b0%e6%89%93%e9%a3%9e%e7%a2%9f%e5%b0%8f%e6%b8%b8%e6%88%8f" onclick="onNavClick(`#用unity3d实现打飞碟小游戏-nav`)" id="用unity3d实现打飞碟小游戏-nav">
									用Unity3D实现【打飞碟小游戏】
								</a>
							</li>
						
						
					
				
			
				
				
					
						
						
						
						
							
								<ul class="collapse" data-toggle="collapse">
							
						
						
							<li>
								<a href="#%e7%9b%b8%e5%85%b3%e9%93%be%e6%8e%a5" onclick="onNavClick(`#相关链接-nav`)" id="相关链接-nav">
									相关链接
								</a>
							</li>
						
						
					
				
			
				
				
					
						
						
						
						
						
							<li>
								<a href="#%e6%b8%b8%e6%88%8f%e8%a7%84%e5%88%99" onclick="onNavClick(`#游戏规则-nav`)" id="游戏规则-nav">
									游戏规则
								</a>
							</li>
						
						
					
				
			
				
				
					
						
						
						
						
							
								<ul class="collapse" data-toggle="collapse">
							
						
						
							<li>
								<a href="#how-to-make-a-simple-%e9%a3%9e%e7%a2%9f" onclick="onNavClick(`#how-to-make-a-simple-飞碟-nav`)" id="how-to-make-a-simple-飞碟-nav">
									How to make a simple 飞碟
								</a>
							</li>
						
						
					
				
			
				
				
					
						
						
						
						
						
							<li>
								<a href="#%e5%b7%a5%e5%8e%82%e6%a8%a1%e5%bc%8f%e5%af%b9%e8%b1%a1%e6%b1%a0%e5%92%8c%e5%af%b9%e8%b1%a1%e5%a4%8d%e7%94%a8" onclick="onNavClick(`#工厂模式对象池和对象复用-nav`)" id="工厂模式对象池和对象复用-nav">
									工厂模式、对象池和对象复用
								</a>
							</li>
						
						
					
				
			
				
				
					
						
						
						
						
						
							<li>
								<a href="#%e7%89%a9%e7%90%86%e5%bc%95%e6%93%8e" onclick="onNavClick(`#物理引擎-nav`)" id="物理引擎-nav">
									物理引擎
								</a>
							</li>
						
						
					
				
			
		</ul>
	</div>

</div>
            
        </div>
    </div>
</div>
<transition name="fade">
    <div v-bind:class="{ 'single-column-drawer-mask': mounted }" v-if="isDrawerOpen" v-on:click="toggleDrawer"></div>
</transition>
<nav ref="navBar" class="navbar sticky-top navbar-light single-column-nav-container">
    <div ref="navBackground" class="nav-background"></div>
    <div class="container container-narrow nav-content">
        <button id="nav_dropdown_btn" class="nav-dropdown-toggle" type="button" v-on:click="toggleDrawer">
            <i class="material-icons">
                menu
            </i>
        </button>
        <a ref="navTitle" class="navbar-brand" href="https://wondrouswisdomcard.gitee.io">
            Wondrous WindomCard&#39;s Blog
        </a>
        
        <button type="button" class="nav-darkmode-toggle" v-on:click="toggleDarkMode">
            <i class="material-icons" v-if="isDarkMode">
                brightness_4
            </i>
            <i class="material-icons" v-else="isDarkMode">
                brightness_7
            </i>
        </button>
        
    </div>
</nav>
<div class="single-column-header-container" ref="pageHead"
     v-bind:style="{ transform: 'translateZ(0px) translateY('+.3*scrollY+'px)', opacity: 1-navOpacity }">
    <a href="https://wondrouswisdomcard.gitee.io">
        <div class="single-column-header-title">Wondrous WindomCard&#39;s Blog</div>
        
        <div class="single-column-header-subtitle">Themed by Diary.</div>
        

    </a>
</div>

            <div id="content">
<div ref="streamContainer" class="stream-container">
    <div class="post-list-container post-list-container-shadow">
        <div class="post">
            
            
            

            <div class="post-head-wrapper-text-only"
                
            >
                <div class="post-title">
                    用Unity3D实现打飞碟游戏
                    
                    <div class="post-meta">
                        
                        <time itemprop="datePublished">
                            2021-10-24 00:00
                        </time>
                        

                        
                            <i class="material-icons" style="">folder</i>
                                <a href="/categories/">[Unity3D]</a>
                                &nbsp;
                        

                        
                            <i class="material-icons" style="">label</i>
                            
                                <a href="/tags/unity3d">Unity3D</a>
                                &nbsp;
                            
                        
                        
                    </div>
                </div>
            </div>
            
            <div class="post-body-wrapper">
                
                <div class="post-body" v-pre>
                
                    <h1 id="用unity3d实现打飞碟小游戏">用Unity3D实现【打飞碟小游戏】</h1>
<hr>
<h2 id="相关链接">相关链接</h2>
<p>项目仓库：https://gitee.com/WondrousWisdomcard/unity3d-homework</p>
<p>项目文档：https://gitee.com/WondrousWisdomcard/unity3d-homework/blob/master/Homework04/%E9%A1%B9%E7%9B%AE%E6%96%87%E6%A1%A3.md</p>
<p>演示视频：</p>
<ul>
<li>
<p>非物理引擎版本：https://www.bilibili.com/video/BV1zT4y1R7TY?spm_id_from=333.999.0.0</p>
</li>
<li>
<p><strong>物理引擎版本</strong>：https://www.bilibili.com/video/BV1Rb4y1h72z?spm_id_from=333.999.0.0</p>
</li>
</ul>
<hr>
<h2 id="游戏规则">游戏规则</h2>
<p>简单地说：这是一个打飞碟小游戏（鼠标打），这是一样非常考验反应和手速的小游戏，不同的小飞碟会从大飞碟中飞出，我们点击小飞碟即可将其轰炸。不同等级的小飞碟的分数不同（黑色飞碟高达5000分！），五回合下来，累计最终得分。</p>
<p><img src="../../images/unity3d3/2.png" alt="20211023204556220"></p>
<p>这次作业的亮点在于引入了工厂模式、对象池和物理引擎，我们将一一介绍，但首先介绍how to make a simple飞碟。</p>
<h3 id="how-to-make-a-simple-飞碟">How to make a simple 飞碟</h3>
<p><img src="../../images/unity3d3/4.png" alt="20211024150239729"></p>
<p>飞碟由一个Y轴压扁的球和一个小球组成，里面包含一个小球，它们的Transform数据如下，内部小球是外部环的子对象，所以它的大小对于外部环的相对大小。</p>
<table>
<thead>
<tr>
<th>外部小环</th>
<th>内部小球</th>
<th>物理属性（外部小环）</th>
</tr>
</thead>
<tbody>
<tr>
<td><img src="../../images/unity3d3/6.png" alt="20211024151110242"></td>
<td><img src="../../images/unity3d3/5.png" alt="20211024151038650"></td>
<td><img src="../../images/unity3d3/7.png" alt="20211024150959545"></td>
</tr>
</tbody>
</table>
<p>我们给它增加一个 RigidBody 组件和 ConstantForce 组件，并为它添加力矩（Torque），这样它就可以轻轻摇摆了。</p>
<p>接下来，我们为它配色，可以用图片（Texture2D），也可以直接创建Material，把设置了颜色的 Material 拖到飞碟上就可以了。</p>
<p>最后把他拖到 Assets 栏形成预制，会轻轻摆动的飞碟就做好了。</p>
<blockquote>
<p>我做的游戏中间有个大飞碟，它使用同样的预制，只不过体型稍大，并设置他不受重力的影响，位置固定（不然它会被小飞碟撞飞）</p>
</blockquote>
<h3 id="工厂模式对象池和对象复用">工厂模式、对象池和对象复用</h3>
<p><strong>工厂模式</strong>（Factory Pattern）是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式，它提供了一种创建对象的最佳方式。在工厂模式中，我们在创建对象时不会对客户端暴露创建逻辑，并且是通过使用一个共同的接口来指向新创建的对象。</p>
<p>在游戏中，因为要创建大量飞碟，我们为飞碟创建了一个飞碟工厂类，控制器通过调用飞碟工厂提供的方法来产生飞碟和释放飞碟。</p>
<p>飞碟工厂对控制器和其他模块隐蔽了飞碟的产生和释放细节。在飞碟工厂内部，我们通过维护两个队列来实现一个飞碟对象池，避免频繁地系统调用来生成对象。</p>
<p>在实际游戏过程中，由于飞碟的需求随着回合数的增加而变大，对象池还是经常处于“不够用”状态，再加上我设计时，每种等级飞碟使用不同的预制，使得对象的复用不是在空闲队列里随便取一个就行的，而是要去的相同等级的飞碟对象（这样它们的预制才是一样的，游戏对象也才符合）。因此每次都需要遍历对象池，寻找合适的空闲飞碟对象。</p>
<p>使用不同预制创建对象出现一个很尴尬的情况，因为每次创建飞碟的等级都是随机选取的，导致可能会出现：空闲池有很多不同等级飞碟，但都无一满足当前所需的飞碟等级。但是，随着飞碟需求数目的增加，这种供不应需的状况就越不会出现，对象池各种等级的空闲飞碟都会存在。</p>
<p>以下是 DiskFactory 类的代码：</p>
<div class="highlight"><pre style="background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c#" data-lang="c#"><span style="color:#8b008b;font-weight:bold">using</span> <span style="color:#008b45;text-decoration:underline">System.Collections</span>;
<span style="color:#8b008b;font-weight:bold">using</span> <span style="color:#008b45;text-decoration:underline">System.Collections.Generic</span>;
<span style="color:#8b008b;font-weight:bold">using</span> <span style="color:#008b45;text-decoration:underline">UnityEngine</span>;

<span style="color:#8b008b;font-weight:bold">public</span> <span style="color:#8b008b;font-weight:bold">class</span> <span style="color:#008b45;font-weight:bold">DiskFactory</span> : MonoBehaviour
{
    <span style="color:#8b008b;font-weight:bold">private</span> List&lt;DiskData&gt; busyDisks;
    <span style="color:#8b008b;font-weight:bold">private</span> List&lt;DiskData&gt; freeDisks;

    <span style="color:#00688b;font-weight:bold">string</span>[] Prefabs = <span style="color:#8b008b;font-weight:bold">new</span> <span style="color:#00688b;font-weight:bold">string</span>[<span style="color:#b452cd">5</span>] {<span style="color:#cd5555">&#34;Prefabs/YellowDisk&#34;</span>, 
        <span style="color:#cd5555">&#34;Prefabs/GreenDisk&#34;</span>, <span style="color:#cd5555">&#34;Prefabs/CyanDisk&#34;</span>, 
        <span style="color:#cd5555">&#34;Prefabs/BlueDisk&#34;</span>, <span style="color:#cd5555">&#34;Prefabs/BlackDisk&#34;</span>};

    <span style="color:#8b008b;font-weight:bold">void</span> Start(){
        busyDisks = <span style="color:#8b008b;font-weight:bold">new</span> List&lt;DiskData&gt;();
        freeDisks = <span style="color:#8b008b;font-weight:bold">new</span> List&lt;DiskData&gt;();
    }

    <span style="color:#8b008b;font-weight:bold">public</span> GameObject GetDisk(<span style="color:#00688b;font-weight:bold">int</span> level){
        GameObject disk = <span style="color:#8b008b;font-weight:bold">null</span>;

        <span style="color:#00688b;font-weight:bold">bool</span> find = <span style="color:#8b008b;font-weight:bold">false</span>;
        <span style="color:#8b008b;font-weight:bold">for</span>(<span style="color:#00688b;font-weight:bold">int</span> i = <span style="color:#b452cd">0</span>; i &lt; freeDisks.Count; i++){
            <span style="color:#8b008b;font-weight:bold">if</span>(freeDisks[i].level == level){
                disk = freeDisks[i].gameObject;
                freeDisks.RemoveAt(i);
                find = <span style="color:#8b008b;font-weight:bold">true</span>;
                <span style="color:#8b008b;font-weight:bold">break</span>;
            }
        }
        
        <span style="color:#8b008b;font-weight:bold">if</span>(find == <span style="color:#8b008b;font-weight:bold">false</span>){
            disk = GameObject.Instantiate&lt;GameObject&gt;(Resources.Load&lt;GameObject&gt;(Prefabs[level - <span style="color:#b452cd">1</span>]), Vector3.zero, Quaternion.identity);
            disk.AddComponent&lt;DiskData&gt;();
            disk.AddComponent&lt;Rigidbody&gt;();
            disk.AddComponent&lt;ConstantForce&gt;();
        }

        <span style="color:#8b008b;font-weight:bold">if</span>(disk != <span style="color:#8b008b;font-weight:bold">null</span>){
            DiskData diskData = disk.GetComponent&lt;DiskData&gt;();
            setDiskData(diskData, level);
            busyDisks.Add(diskData);
        }

        <span style="color:#8b008b;font-weight:bold">return</span> disk;
    }

    <span style="color:#8b008b;font-weight:bold">public</span> <span style="color:#8b008b;font-weight:bold">void</span> FreeDisk(GameObject disk){
        <span style="color:#8b008b;font-weight:bold">foreach</span>(DiskData diskData <span style="color:#8b008b;font-weight:bold">in</span> busyDisks){
            <span style="color:#8b008b;font-weight:bold">if</span>(diskData.gameObject.GetInstanceID() == disk.GetInstanceID()){
                disk.SetActive(<span style="color:#8b008b;font-weight:bold">false</span>);
                busyDisks.Remove(diskData);
                freeDisks.Add(diskData);
                <span style="color:#8b008b;font-weight:bold">break</span>;
            }
        }
    }

    <span style="color:#8b008b;font-weight:bold">public</span> <span style="color:#8b008b;font-weight:bold">void</span> setDiskData(DiskData diskData, <span style="color:#00688b;font-weight:bold">int</span> level){
        <span style="color:#8b008b;font-weight:bold">if</span>(level &lt;= <span style="color:#b452cd">1</span>){
            diskData.level = <span style="color:#b452cd">1</span>;
            diskData.mass = <span style="color:#b452cd">1.0F</span> + Random.Range(-<span style="color:#b452cd">1F</span>, <span style="color:#b452cd">1F</span>) * <span style="color:#b452cd">0.4F</span>;
            diskData.score = <span style="color:#b452cd">50</span>;
            diskData.speed = <span style="color:#8b008b;font-weight:bold">new</span> Vector3(Random.Range(-<span style="color:#b452cd">0.1F</span>, <span style="color:#b452cd">0.1F</span>), Random.Range(-<span style="color:#b452cd">0.1F</span>, <span style="color:#b452cd">0.1F</span>), Random.Range(-<span style="color:#b452cd">0.1F</span>, <span style="color:#b452cd">0.1F</span>));
            diskData.force = <span style="color:#8b008b;font-weight:bold">new</span> Vector3(Random.Range(-<span style="color:#b452cd">1F</span>, <span style="color:#b452cd">1F</span>), Random.Range(-<span style="color:#b452cd">1F</span>, <span style="color:#b452cd">1F</span>), Random.Range(-<span style="color:#b452cd">1F</span>, <span style="color:#b452cd">1F</span>));
        }
        <span style="color:#8b008b;font-weight:bold">else</span> <span style="color:#8b008b;font-weight:bold">if</span>(level == <span style="color:#b452cd">2</span>){
            diskData.level = <span style="color:#b452cd">2</span>;
            diskData.mass = <span style="color:#b452cd">2.0F</span> + Random.Range(-<span style="color:#b452cd">1F</span>, <span style="color:#b452cd">1F</span>) * <span style="color:#b452cd">0.8F</span>;
            diskData.score = <span style="color:#b452cd">100</span>;
            diskData.speed = <span style="color:#8b008b;font-weight:bold">new</span> Vector3(Random.Range(-<span style="color:#b452cd">2F</span>, <span style="color:#b452cd">2F</span>), Random.Range(-<span style="color:#b452cd">2F</span>, <span style="color:#b452cd">2F</span>), Random.Range(-<span style="color:#b452cd">2F</span>, <span style="color:#b452cd">2F</span>));
            diskData.force = <span style="color:#8b008b;font-weight:bold">new</span> Vector3(Random.Range(-<span style="color:#b452cd">2F</span>, <span style="color:#b452cd">2F</span>), Random.Range(-<span style="color:#b452cd">2F</span>, <span style="color:#b452cd">2F</span>), Random.Range(-<span style="color:#b452cd">2F</span>, <span style="color:#b452cd">2F</span>));
        }
        <span style="color:#8b008b;font-weight:bold">else</span> <span style="color:#8b008b;font-weight:bold">if</span>(level == <span style="color:#b452cd">3</span>){
            diskData.level = <span style="color:#b452cd">3</span>;
            diskData.mass = <span style="color:#b452cd">3.0F</span> + Random.Range(-<span style="color:#b452cd">1F</span>, <span style="color:#b452cd">1F</span>) * <span style="color:#b452cd">1.6F</span>;
            diskData.score = <span style="color:#b452cd">500</span>;
            diskData.speed = <span style="color:#8b008b;font-weight:bold">new</span> Vector3(Random.Range(-<span style="color:#b452cd">5F</span>, <span style="color:#b452cd">5F</span>), Random.Range(-<span style="color:#b452cd">5F</span>, <span style="color:#b452cd">5F</span>), Random.Range(-<span style="color:#b452cd">5F</span>, <span style="color:#b452cd">5F</span>));
            diskData.force = <span style="color:#8b008b;font-weight:bold">new</span> Vector3(Random.Range(-<span style="color:#b452cd">5F</span>, <span style="color:#b452cd">5F</span>), Random.Range(-<span style="color:#b452cd">5F</span>, <span style="color:#b452cd">5F</span>), Random.Range(-<span style="color:#b452cd">5F</span>, <span style="color:#b452cd">5F</span>));

        }
        <span style="color:#8b008b;font-weight:bold">else</span> <span style="color:#8b008b;font-weight:bold">if</span>(level == <span style="color:#b452cd">4</span>){
            diskData.level = <span style="color:#b452cd">4</span>;
            diskData.mass = <span style="color:#b452cd">4.0F</span> + Random.Range(-<span style="color:#b452cd">1F</span>, <span style="color:#b452cd">1F</span>) * <span style="color:#b452cd">2.4F</span>;
            diskData.score = <span style="color:#b452cd">1000</span>;
            diskData.speed = <span style="color:#8b008b;font-weight:bold">new</span> Vector3(Random.Range(-<span style="color:#b452cd">10F</span>, <span style="color:#b452cd">10F</span>), Random.Range(-<span style="color:#b452cd">10F</span>, <span style="color:#b452cd">10F</span>), Random.Range(-<span style="color:#b452cd">10F</span>, <span style="color:#b452cd">10F</span>));
            diskData.force = <span style="color:#8b008b;font-weight:bold">new</span> Vector3(Random.Range(-<span style="color:#b452cd">10F</span>, <span style="color:#b452cd">10F</span>), Random.Range(-<span style="color:#b452cd">10F</span>, <span style="color:#b452cd">10F</span>), Random.Range(-<span style="color:#b452cd">10F</span>, <span style="color:#b452cd">10F</span>));

        } 
        <span style="color:#8b008b;font-weight:bold">else</span> <span style="color:#8b008b;font-weight:bold">if</span>(level &gt;= <span style="color:#b452cd">5</span>){
            diskData.level = <span style="color:#b452cd">5</span>;
            diskData.mass = <span style="color:#b452cd">5.0F</span> + Random.Range(-<span style="color:#b452cd">1F</span>, <span style="color:#b452cd">1F</span>) * <span style="color:#b452cd">4.0F</span>;
            diskData.score = <span style="color:#b452cd">5000</span>;
            diskData.speed = <span style="color:#8b008b;font-weight:bold">new</span> Vector3(Random.Range(-<span style="color:#b452cd">20F</span>, <span style="color:#b452cd">20F</span>), Random.Range(-<span style="color:#b452cd">20F</span>, <span style="color:#b452cd">20F</span>), Random.Range(-<span style="color:#b452cd">20F</span>, <span style="color:#b452cd">20F</span>));
            diskData.force = <span style="color:#8b008b;font-weight:bold">new</span> Vector3(Random.Range(-<span style="color:#b452cd">20F</span>, <span style="color:#b452cd">20F</span>), Random.Range(-<span style="color:#b452cd">20F</span>, <span style="color:#b452cd">20F</span>), Random.Range(-<span style="color:#b452cd">20F</span>, <span style="color:#b452cd">20F</span>));
        }
    }
}
</code></pre></div><h3 id="物理引擎">物理引擎</h3>
<p>使用物理引擎，我们可以模拟现实世界中物理运动，碰撞的效果。</p>
<p>**物理引擎（Physics Engine）**是一个软件组件，它将游戏世界对象赋予现实世界物理属性（重量、形状等），并抽象为刚体（Rigid）模型（也包括滑轮、绳索等），使得游戏物体在力的作用下，仿真现实世界的运动及其之间的碰撞过程。即在牛顿经典力学模型基础之上，通过简单的 API 计算游戏物体的运动、旋转和碰撞，现实的运动与碰撞的效果。</p>
<p>在游戏中，我们使用了 Uniy3D 提供的刚体组件 RigidBody 和 恒力组件 ConstantFroce，前者可以用来设置物体的重量，速度，是否受重力影响等等属性，后者可以为对象提供一个方向的恒力（Force），力矩（Torque）。</p>
<p>我们可以直接在游戏对象上添加这些组件，并可视化编辑：</p>
<p><img src="../../images/unity3d3/8.png" alt="20211024155155983"></p>
<p>也可以通过代码实现：（针对游戏过程中动态创建的对象）</p>
<p>例如以下几行，分别是设置速度、力、力矩，获取方法都是通过游戏对象的<code>GetComponent&lt;&gt;()</code>函数。</p>
<div class="highlight"><pre style="background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c#" data-lang="c#"><span style="color:#8b008b;font-weight:bold">this</span>.gameObject.GetComponent&lt;Rigidbody&gt;().velocity = speed;
<span style="color:#8b008b;font-weight:bold">this</span>.gameObject.GetComponent&lt;ConstantForce&gt;().force = force;
<span style="color:#8b008b;font-weight:bold">this</span>.gameObject.GetComponent&lt;ConstantForce&gt;().torque = <span style="color:#8b008b;font-weight:bold">new</span> Vector3(<span style="color:#b452cd">0.2F</span>, <span style="color:#b452cd">0</span>, -<span style="color:#b452cd">0.2F</span>);
</code></pre></div>
                    
                    <HR width="100%" id="EOF">
		    <p style="color:#777;">Last modified on 2021-10-24</p>
                    
                </div>
            </div>
            
            
            <nav class="post-pagination">

                
                <a class="newer-posts" href="https://wondrouswisdomcard.gitee.io/posts/unity3d4/">
			Next<br>用Unity3D实现【智能巡逻兵】
                </a>
                
                
                
                <a class="older-posts" href="https://wondrouswisdomcard.gitee.io/posts/unity3d2/">
			Previous<br>用Unity3D实现【牧师与魔鬼过河】
                </a>
                
            </nav>
            <div class="post-comment-wrapper">
                
<div class="comments">
    <vue-disqus shortname="Your disqus short name."></vue-disqus>
</div>
<noscript><noscript>Please activate JavaScript to view comments.</noscript></noscript>
<a href="https://disqus.com/" class="dsq-brlink">Comments powered by <span class="logo-disqus">Disqus</span></a>



<div id="gitalk-container"></div>






            </div>
        </div>
    </div>
</div>

            </div><div id="single-column-footer">
Hugo Theme <a href="https://github.com/amazingrise/hugo-theme-diary">Diary</a> by <a href="https://amazingrise.net">Rise</a>
<br>
Ported from <a href="https://mak1t0.cc/" target="_blank" rel="noreferrer noopener">Makito</a>'s <a href="https://github.com/SumiMakito/hexo-theme-journal/" target="_blank" rel="noreferrer noopener">Journal.</a> <br>
<br>

&copy;
	
	This is a customized copyright.
	
</div>
            </div>
    <script>
let app;

app = new Vue({
    el: '#app',
    data: {
        scrollY: 0,
        navOpacity: 0,
        isDrawerOpen: false,
        mounted: false,
        isDarkMode: false
    },
    methods: {
            sgn(t, x) {
                let k = 1. / (1. - 2 * t);
                if (x <= t) return 0;
                else if (x >= 1 - t) return 1;
                else {
                    return k * (x - t);
                }
            },
            handleScroll() {
                this.scrollY = window.scrollY;
                this.navOpacity = this.sgn(.0, Math.min(1, Math.max(0, window.scrollY / (this.pageHeadHeight() - this.navBarHeight() * 0.8))));
                const {navBar, navBackground, navTitle, extraContainer, streamContainer} = this.$refs;

                if (this.navOpacity >= 1) {
                    navBackground.style.opacity = 1;
                    navTitle.style.opacity = 1;
                } else {
                    navBackground.style.opacity = 0;
                    navTitle.style.opacity = 0;
                }
            },
            handleResize() {
                const {navBar, navBackground, navTitle, extraContainer, streamContainer} = this.$refs;
                extraContainer.style.left = (streamContainer.offsetWidth - extraContainer.offsetWidth) + 'px';
            },
            navBarHeight() {
                return this.$refs.navBar.offsetHeight;
            },
            pageHeadHeight() {
                return this.$refs.pageHead.offsetHeight;
            },
            toggleDrawer() {
                this.isDrawerOpen = !this.isDrawerOpen;
                document.getElementsByTagName('html')[0].style.overflow = this.isDrawerOpen ? 'hidden' : 'unset';
            },
            closeDrawer() {
                this.isDrawerOpen = false;
                document.getElementsByTagName('html')[0].style.overflow = this.isDrawerOpen ? 'hidden' : 'unset';
            },
            toggleDarkMode() {
                this.isDarkMode = !this.isDarkMode;
                if (this.isDarkMode==true){
                    document.cookie = "night=1;path=/";
                    document.body.classList.add("night");
                } else {
                    document.cookie = "night=0;path=/";
                    document.body.classList.remove("night");
                }
            }
    },
    created() {
        window.addEventListener('scroll', this.handleScroll);
        window.addEventListener('resize', this.handleResize);
        window._nonDesktop = function () {
            let check = false;
            (function (a) {
                if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true;
            })(navigator.userAgent || navigator.vendor || window.opera);
            return check;
        };
        
        var night = document.cookie.replace(/(?:(?:^|.*;\s*)night\s*\=\s*([^;]*).*$)|^.*$/, "$1");
        if (night==""){
            if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
                
            }
        }else{
            
            if (night=="1") {
                this.toggleDarkMode();
            }
        }
    },
    mounted() {
        this.handleScroll();
        this.handleResize();
        this.mounted = true;

        
    },
    destroyed() {
        window.removeEventListener('scroll', this.handleScroll);
        window.removeEventListener('resize', this.handleResize);
    }
});
</script>

<script src="https://wondrouswisdomcard.gitee.io/js/journal.js"></script>
    </body>
</html>
